home *** CD-ROM | disk | FTP | other *** search
- /* LogLibrary.c */
- /*
- * LogLibrary.c
- * Copyright © 1992-95 Apple Computer Inc. All Rights Reserved.
- * Programmed by Martin Minow,
- * Internet: minow@apple.com
- * AppleLink: MINOW
- *
- * Edit History
- * This library implements a drop-in logging capability for device drivers,
- * callback functions, applications, and all other Power Macintosh code segments
- * running under a version of system software that supports the System Name Registry
- * and Driver Services libraries defined in Designing PCI Cards and Drivers for
- * Power Macintosh Computers.
- *
- * The overall philosophy is that an application or driver allocates a record in
- * the resident pool that contains a small preamble and one or more short blocks of
- * data. The driver logs data to the log area, where each log record contains an
- * identification value, a timestamp and up to eight longwords of data. The data
- * entry is self-formatting, so a generic log display application may be written.
- *
- * To permit logging from primary interupt level (which precludes using Software
- * Interrupts), the log record common area is protected by a critical section
- * (test and set) variable. The log is "lossy" in that failure to enter the
- * critical section will lose data, but will not stall or block the caller.
- *
- * This function will crash (or fail to load) if Driver Services and/or Name
- * Registry functions are unavailable.
- *
- * The LogData library may be linked into a PCI Device Driver: it does not
- * call any Macintosh Toolbox functions.
- *
- * If compiled under Power PC (native), LogLibrary generates the actual
- * log support. If compiled for the 68000 architecture, it generates Mixed
- * Mode "glue" routines that will link the 68000 functions to the LogData
- * shared library.
- *
- * Usage:
- * PowerPC (native):
- * Include "LogLibrary.h" in all compilations.
- * Either compile LogLibrary.c or include LogLibrary (shared library).
- * 68000 emulation
- * Include "LogLibrary.h" in all compilations.
- * Compile LogLibrary.c (or include an object).
- * Make LogLibrary known to the executing program, possibly by storing
- * it in the Extensions folder.
- *
- * Edit History
- * 1995.03.28 MM CompareAndSwap screw-up.
- * 1995.03.31 MM Removed UpTime return from CopyLogEntry (only the dcmd needs it)
- * Added LogLibraryUpTime to return UpTime in nanoseconds for 68000
- * functions.
- * ResolveLogLibraryLinkage is now a static function: it was global.
- * 1995.04.07 MM Some compilers mis-handle functions returning structures. Store
- * UpTime returned values in a volatile local variable before using
- * them in a function call.
- */
-
- #include "LogLibrary.h"
- #define LOG (*logRecordPtr)
- #ifndef TEST_DCMD
- #ifdef MPW
- #define TEST_DCMD 1
- #else
- #define TEST_DCMD 0
- #endif /* MPW */
- #endif /* TEST_DCMD undefined */
- #if GENERATINGPOWERPC
- #define GENERATE_GLUE 0 /* Generate the actual library */
- #else
- #define GENERATE_GLUE 1 /* Generate Mixed Mode glue */
- #if TEST_DCMD
- /*
- * For testing with the dcmd only
- */
- extern void PutSigned(
- SInt32 value
- );
- extern void PutPascalString(
- ConstStr255Param datum
- );
- extern void PutLine(void);
- #endif /* dcmd testing */
- #endif /* Generating Mixed Mode glue */
-
- #ifndef TRUE
- #define TRUE 1
- #define FALSE 0
- #endif
- #define EOS '\0'
- /*
- * "name" is used by the Name Registry.
- */
- #define kReservedPropertyName "name"
-
-
- #if GENERATE_GLUE
- #ifndef THINK_C /* Temp until headers stabalize */
- #include <MixedMode.h>
- #include <CodeFragments.h>
- #endif
-
- /*
- * Definitions for the Glue library.
- */
- #define kLogLinkFailed ((UniversalProcPtr) (-1L))
-
- typedef pascal LogRecordPtr (*MakeLogRecordProcPtr)
- (const LogRecordNamePtr, UInt32);
- typedef pascal LogRecordPtr (*GetLogRecordProcPtr)
- (const LogRecordNamePtr);
- typedef pascal OSErr (*StoreLogEntryProcPtr)
- (LogRecordPtr, const LogEntryPtr);
- typedef pascal OSErr (*ReadLogEntryProcPtr)
- (LogRecordPtr, LogEntryPtr);
- typedef pascal Boolean32 (*EnableLogRecordProcPtr)
- (LogRecordPtr, Boolean32);
- typedef pascal Boolean32 (*PreserveLogRecordProcPtr)
- (LogRecordPtr, Boolean32);
- typedef pascal UInt32 (*GetLogSemaphoreLostCounterProcPtr)
- (LogRecordPtr);
- typedef pascal OSErr (*LogRecordIterateCreateProcPtr)
- (LogRecordIterPtr);
- typedef pascal void (*LogRecordIterateDisposeProcPtr)
- (LogRecordIterPtr);
- typedef pascal LogRecordPtr (*LogRecordIterateProcPtr)
- (LogRecordIterPtr);
- typedef pascal OSErr (*CopyLogEntryProcPtr) /* DCMD only */
- (LogRecordPtr, UInt32, LogEntryPtr);
- typedef pascal OSErr (*CopyLogRecordProcPtr) /* DCMD only */
- (const LogRecordPtr, LogRecordPtr);
- typedef pascal void (*LogLibraryUpTimeProcPtr) /* DCMD only */
- (Nanoseconds *);
- typedef pascal void (*LogLibraryAbsoluteToNanosecondsProcPtr)
- (const AbsoluteTime *sourcePtr, Nanoseconds *resultPtr);
- /* */
- static OSErr ResolveLogLibraryLinkage(
- ConstStr255Param symbolRDName,
- UniversalProcPtr *uppPtr
- );
- #else /* The real library */
- /*
- * These are Routine Descriptors for the functions that are always in Power PC
- * native code, but are called from glue routines. Note that the _rd... symbols
- * must be global so that they can be resolved by the 68000 code. Hmm, is this
- * the correct solution?
- */
- enum {
- uppMakeLogRecordProcInfo = kPascalStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof (LogRecordPtr)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(const LogRecordNamePtr)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof (UInt32)))
- };
- const RoutineDescriptor _rdMakeLogRecord =
- BUILD_ROUTINE_DESCRIPTOR(uppMakeLogRecordProcInfo, MakeLogRecord);
- /* */
- enum {
- uppGetLogRecordPtrProcInfo = kPascalStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof (LogRecordPtr)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(const LogRecordNamePtr)))
- };
- const RoutineDescriptor _rdGetLogRecordPtr =
- BUILD_ROUTINE_DESCRIPTOR(uppGetLogRecordPtrProcInfo, GetLogRecordPtr);
- /* */
- enum {
- uppStoreLogEntryProcInfo = kPascalStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof (OSErr)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordPtr)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof (LogEntryPtr)))
- };
- const RoutineDescriptor _rdStoreLogEntry =
- BUILD_ROUTINE_DESCRIPTOR(uppStoreLogEntryProcInfo, StoreLogEntry);
- /* */
- enum {
- uppReadLogEntryProcInfo = kPascalStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof (OSErr)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordPtr)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof (LogEntryPtr)))
- };
- const RoutineDescriptor _rdReadLogEntry =
- BUILD_ROUTINE_DESCRIPTOR(uppReadLogEntryProcInfo, ReadLogEntry);
- /* */
- enum {
- uppEnableLogRecordProcInfo = kPascalStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof (Boolean32)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordPtr)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof (Boolean32)))
- };
- const RoutineDescriptor _rdEnableLogRecord =
- BUILD_ROUTINE_DESCRIPTOR(uppEnableLogRecordProcInfo, EnableLogRecord);
- /* */
- enum {
- uppPreserveLogRecordProcInfo = kPascalStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof (Boolean32)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordPtr)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof (Boolean32)))
- };
- const RoutineDescriptor _rdPreserveLogRecord =
- BUILD_ROUTINE_DESCRIPTOR(uppPreserveLogRecordProcInfo, PreserveLogRecord);
- /* */
- enum {
- uppGetLogSemaphoreLostCounterProcInfo = kPascalStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof (UInt32)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordPtr)))
- };
- const RoutineDescriptor _rdGetLogSemaphoreLostCounter =
- BUILD_ROUTINE_DESCRIPTOR(
- uppGetLogSemaphoreLostCounterProcInfo,
- GetLogSemaphoreLostCounter
- );
- /* */
- enum {
- uppLogRecordIterateCreateProcInfo = kPascalStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof (OSErr)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordIterPtr)))
- };
- const RoutineDescriptor _rdLogRecordIterateCreate =
- BUILD_ROUTINE_DESCRIPTOR(
- uppLogRecordIterateCreateProcInfo,
- LogRecordIterateCreate
- );
- /* */
- enum {
- uppLogRecordIterDisposeProcInfo = kPascalStackBased
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordIterPtr)))
- };
- const RoutineDescriptor _rdLogRecordIterateDispose =
- BUILD_ROUTINE_DESCRIPTOR(
- uppLogRecordIterDisposeProcInfo,
- LogRecordIterateDispose
- );
- /* */
- enum {
- uppLogRecordIterateProcInfo = kPascalStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof (LogRecordPtr)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordIterPtr)))
- };
- const RoutineDescriptor _rdLogRecordIterate =
- BUILD_ROUTINE_DESCRIPTOR(
- uppLogRecordIterateProcInfo,
- LogRecordIterate
- );
-
- /*
- * These are for the primary use of the DCMD.
- */
- enum {
- uppCopyLogEntryProcInfo = kPascalStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof (OSErr)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordPtr)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof (UInt32)))
- | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof (LogEntryPtr)))
- };
- const RoutineDescriptor _rdCopyLogEntry =
- BUILD_ROUTINE_DESCRIPTOR(uppCopyLogEntryProcInfo, CopyLogEntry);
-
- enum {
- uppCopyLogRecordProcInfo = kPascalStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof (OSErr)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordPtr)))
- | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof (LogRecordPtr)))
- };
- const RoutineDescriptor _rdCopyLogRecordInfo =
- BUILD_ROUTINE_DESCRIPTOR(uppCopyLogRecordProcInfo, CopyLogRecordInfo);
-
- enum {
- uppLogLibraryUpTimeProcInfo = kPascalStackBased
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (Nanoseconds *)))
- };
- const RoutineDescriptor _rdLogLibraryUpTime =
- BUILD_ROUTINE_DESCRIPTOR(uppLogLibraryUpTimeProcInfo, LogLibraryUpTime);
-
- enum {
- uppLogLibraryAbsoluteToNanosecondsProcInfo = kPascalStackBased
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (const AbsoluteTime *)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (Nanoseconds *)))
- };
- const RoutineDescriptor _rdLogLibraryAbsoluteToNanoseconds =
- BUILD_ROUTINE_DESCRIPTOR(uppLogLibraryUpTimeProcInfo, LogLibraryAbsoluteToNanoseconds);
-
- /* */
- static RegEntryID gLogEntryID;
- typedef enum {
- kFirstCall = 0,
- kLogEntryOK,
- kLogEntryFailed
- } FoundLogEntryStatus;
- static FoundLogEntryStatus gFoundLogEntryStatus;
-
- static LogRecordPtr FindLogRecordPtr(
- const LogRecordNamePtr logRecordNamePtr
- );
- static LogRecordPtr CreateLogRecord(
- const LogRecordNamePtr logRecordNamePtr, /* Driver Log name */
- UInt32 nEntries /* Number of Log entries */
- );
- static Boolean FindOrCreateLogRegistryEntryID(void);
-
- #endif /* GENERATE_GLUE */
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * MakeLogRecord
- *
- * The first time this function is called after the system is started, it creates a
- * log record for this name. The log is initially enabled, and deletes overflow at the
- * start. It thus retains the *end* of the log -- this is useful for ongoing logging,
- * but may lose the start of a disaster sequence (as it records the flow of errors
- * through the system, rather than the intial cause.
- *
- * Returns the LogRecordPtr for this log, or NULL if unsuccessful.
- *
- * This function must be called in a context that can allocate memory. The first
- * call from a 68000 architecture module must be able to load a shared library.
- */
- pascal LogRecordPtr
- MakeLogRecord(
- const LogRecordNamePtr logRecordNamePtr, /* Log name (C-string) */
- UInt32 nEntries /* Number of Log entries */
- )
- {
- LogRecordPtr logRecordPtr; /* This log record */
- #if GENERATE_GLUE
- MakeLogRecordProcPtr upp;
-
- if (ResolveLogLibraryLinkage(
- "\p_rdMakeLogRecord",
- (UniversalProcPtr *) &upp)
- != noErr)
- logRecordPtr = NULL;
- else {
- logRecordPtr = (*upp)(logRecordNamePtr, nEntries);
- }
- #else
- logRecordPtr = CreateLogRecord(logRecordNamePtr, nEntries);
- /*
- * This is either a new log record or one already created. Grab the
- * semaphore (to protect against an asynchronous process trying to log
- * to us) and initialze the log record if it is not already present.
- */
- if (CompareAndSwap(0, 1, &LOG.semaphore) == FALSE) /* Grab semaphore */
- IncrementAtomic((SInt32 *) &LOG.lostLockCounter); /* Oops, it's busy */
- else { /* Nope, we got it */
- if (LOG.entryMaxIndex == 0) {
- /*
- * Fresh start. Save the logName, set the flag. All other fields
- * are zero.
- */
- LOG.entryMaxIndex = nEntries + 1;
- LOG.sequenceCounter = 1;
- CStrNCopy(
- LOG.logName,
- (char *) logRecordNamePtr,
- sizeof LOG.logName - 1
- );
- LOG.flags = ( (1 * kLogDataEnabledMask)
- | (0 * kLogDataPreserveFirstMask)
- );
- }
- LOG.semaphore = 0; /* Free the semaphore */
- }
- #endif /* GENERATE_GLUE */
- return (logRecordPtr);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * GetLogRecordPtr
- *
- * Find the address of the LogRecord in the System Registry.
- *
- * The first call from a 68000 architecture module must be able to load a shared
- * library.
- */
- pascal LogRecordPtr
- GetLogRecordPtr(
- const LogRecordNamePtr logRecordNamePtr /* Log name (C-string) */
- )
- {
- LogRecordPtr logRecordPtr; /* This log record */
- #if GENERATE_GLUE
- GetLogRecordProcPtr upp;
-
- if (ResolveLogLibraryLinkage(
- "\p_rdGetLogRecordPtr",
- (UniversalProcPtr *) &upp)
- != noErr)
- logRecordPtr = NULL;
- else {
- logRecordPtr = (*upp)(logRecordNamePtr);
- }
- #else
- logRecordPtr = FindLogRecordPtr(logRecordNamePtr);
- #endif /* GENERATE_GLUE */
- return (logRecordPtr);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * CopyLogRecordInfo
- *
- * This function copies the permanent part of the LogRecord (srcLogRecordPtr) to a
- * caller-designated area (dstLogRecordPtr). It is only for the benefit of the DCMD.
- * It returns noErr if successful, paramErr if either the source or destination parameters
- * are incorrect, or a Shared Library Manager error. This function ignores the interlock
- * semaphore. Thus, it may return inconstent data. It does not copy the first LogRecordEntry.
- *
- * Only the DCMD is permitted to call this function!
- */
- pascal OSErr
- CopyLogRecordInfo(
- const LogRecordPtr srcLogRecordPtr,
- LogRecordPtr dstLogRecordPtr
- )
- {
- OSErr status;
- #if GENERATE_GLUE
- CopyLogRecordProcPtr upp;
-
- status = ResolveLogLibraryLinkage(
- "\p_rdCopyLogRecordInfo",
- (UniversalProcPtr *) &upp);
- if (status == noErr)
- status = (*upp)(srcLogRecordPtr, dstLogRecordPtr);
- #else
- if (srcLogRecordPtr == NULL || dstLogRecordPtr == NULL)
- status = paramErr;
- else {
- BlockCopy(
- srcLogRecordPtr,
- dstLogRecordPtr,
- sizeof (LogRecord) - sizeof (LogEntryRecord)
- );
- status = noErr;
- }
- #endif /* GENERATE_GLUE */
- return (status);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * (LogString)
- *
- * This is a function version of the LogEntryString macro.
- */
- pascal OSErr
- (LogString)(
- LogRecordPtr logRecordPtr, /* This log record */
- OSType idCode, /* Entry identifier */
- ConstStr255Param string /* The datum */
- )
- {
- OSErr status;
-
- status = WriteLogEntry(logRecordPtr, idCode, LogStringFormat, string);
- return (status);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * (LogStatusString)
- *
- * This is a function version of the LogDataStatusString macro.
- */
- pascal OSErr
- (LogStatusString)(
- LogRecordPtr logRecordPtr, /* This log record */
- OSType idCode, /* Entry identifier */
- OSErr callerStatus, /* Status error code */
- ConstStr255Param string /* The datum */
- )
- {
- OSErr status;
-
- status = WriteLogEntry(
- logRecordPtr,
- idCode,
- LogStatusFormat,
- (signed long) callerStatus,
- string
- );
- return (status);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * WriteLogEntry
- *
- * This function logs data if logging is enabled.
- * idCode A user-controlled value, by convention an OSType (4-byte
- * character), that identifies this entry. The display program
- * prints it.
- * format The format of the remaining data: kLogFormatString if the
- * datum is a pascal string, otherwise, it is as created by the
- * LogFormat macro.
- * ... Additional data as needed. These values must be cast to
- * longwords to prevent ThinkC/MPW incompatibilities.
- * Note: The MixedMode Manager does not support variable-length argument lists.
- * Hence, this function is always in the "current" architecture.
- */
- OSErr
- WriteLogEntry(
- LogRecordPtr logRecordPtr, /* This log record */
- OSType idCode,
- UInt32 format,
- ...
- )
- {
- va_list argPtr;
- register UInt32 *destPtr;
- LogEntryRecord theEntry;
- UInt16 maxString;
- register UInt16 stringLength;
- register UInt16 i;
- UInt16 thisFormat;
- StringPtr theString;
- OSErr status;
- #define ENTRY (theEntry)
-
- if (logRecordPtr == NULL || (LOG.flags & kLogDataEnabledMask) == 0)
- status = noErr;
- else {
- ENTRY.idCode = idCode;
- ENTRY.format = format;
- va_start(argPtr, format);
- destPtr = ENTRY.data;
- maxString = sizeof (ENTRY.data);
- while (maxString > 0) {
- thisFormat = format & kLogFormatMask;
- switch (thisFormat) {
- case kLogFormatEnd:
- goto exitLoop;
- case kLogFormatString:
- theString = va_arg(argPtr, StringPtr);
- if (theString == NULL)
- theString = "\p{null}";
- stringLength = theString[0];
- if (stringLength >= maxString)
- stringLength = maxString - 1;
- for (i = 1; i <= stringLength; i++)
- ((Ptr) destPtr)[i] = theString[i];
- ((Ptr) destPtr)[0] = stringLength;
- goto exitLoop;
- default: /* Signed or unsigned long value */
- *destPtr++ = va_arg(argPtr, unsigned long);
- format >>= kLogFormatShift;
- maxString -= sizeof (unsigned long);
- break;
- }
- }
- exitLoop: va_end(nextArg);
- status = StoreLogEntry(logRecordPtr, &theEntry);
- } /* If the LogData record exists */
- return (status);
- #undef ENTRY
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * StoreLogEntry
- *
- * Store a formatted LogEntryRecord in the log. This is the only routine that
- * writes the log entry. Normally, it is only called by WriteLogData.
- */
- pascal OSErr
- StoreLogEntry(
- LogRecordPtr logRecordPtr, /* This log record */
- const LogEntryPtr logEntryPtr /* Gets this entry */
- )
- {
- OSErr status;
- #if GENERATE_GLUE
- StoreLogEntryProcPtr upp;
-
- status = ResolveLogLibraryLinkage(
- "\p_rdStoreLogEntry",
- (UniversalProcPtr *) &upp
- );
- if (status == noErr)
- status = (*upp)(logRecordPtr, logEntryPtr);
- #else
- UInt32 putIndex;
- UInt32 getIndex;
- #define ENTRY (*logEntryPtr)
-
- if (logRecordPtr == NULL || (LOG.flags & kLogDataEnabledMask) == 0)
- status = noErr;
- else {
- ENTRY.eventTime = UpTime();
- ENTRY.sequence = IncrementAtomic((SInt32 *) &LOG.sequenceCounter);
- if (CompareAndSwap(0, 1, &LOG.semaphore) == FALSE) { /* Grab semaphore */
- IncrementAtomic((SInt32 *) &LOG.lostLockCounter); /* Oops, it's busy*/
- status = fBsyErr; /* Return "busy" */
- }
- else { /* Nope, we got it */
- /*
- * The ring buffer is designed so that put == get implies empty
- * and pointers are always incremented before use.
- */
- putIndex = LOG.entryPutIndex + 1;
- if (putIndex >= LOG.entryMaxIndex) {
- putIndex = 0;
- LOG.flags |= kLogDataWrapAroundMask;
- }
- if (putIndex == LOG.entryGetIndex) { /* Did it fill? */
- if ((LOG.flags & kLogDataPreserveFirstMask) != 0)
- status = writErr; /* Keeping first */
- else {
- /*
- * We want to retain the latest entry. Do this by
- * advancing the "get" pointer as if the earliest entry
- * has been read. Then jump around the if bracket to store
- * this datum.
- */
- getIndex = LOG.entryGetIndex + 1;
- if (getIndex >= LOG.entryMaxIndex)
- getIndex = 0;
- LOG.entryGetIndex = getIndex;
- goto storeDatum;
- }
- }
- else {
- storeDatum: LOG.entries[putIndex] = ENTRY;
- LOG.entryPutIndex = putIndex;
- status = noErr; /* Data stored ok */
- }
- LOG.semaphore = 0; /* Free semaphore */
- }
- }
- #endif /* GENERATE_GLUE */
- return (status);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * ReadLogEntry
- *
- * Read the next LogRecord entry. This returns a copy of the entry, if one is
- * available. The following status may be returned:
- * noErr Valid data was returned.
- * readErr No data is available.
- * fBsyErr The semaphore was locked by another function (presumable writing
- * into the log). Try again later.
- * other Code Fragment error.
- */
- pascal OSErr
- ReadLogEntry(
- LogRecordPtr logRecordPtr, /* This log record */
- LogEntryPtr thisLogEntry /* Store entry here */
- )
- {
- OSErr status;
- #if GENERATE_GLUE
- ReadLogEntryProcPtr upp;
-
- status = ResolveLogLibraryLinkage(
- "\p_rdReadLogEntry",
- (UniversalProcPtr *) &upp
- );
- if (status == noErr)
- status = (*upp)(logRecordPtr, thisLogEntry);
- #else
- UInt32 getIndex;
-
- status = readErr; /* Presume no data */
- if (logRecordPtr != NULL && thisLogEntry != NULL) {
- if (CompareAndSwap(0, 1, &LOG.semaphore) == FALSE) { /* Grab semaphore */
- IncrementAtomic((SInt32 *) &LOG.lostLockCounter); /* Oops, it's busy*/
- status = fBsyErr; /* Inform caller */
- }
- else { /* Nope, we got it */
- getIndex = LOG.entryGetIndex;
- if (getIndex != LOG.entryPutIndex) { /* Not empty? */
- status = noErr;
- if (++getIndex >= LOG.entryMaxIndex)
- getIndex = 0;
- *thisLogEntry = LOG.entries[getIndex];
- LOG.entryGetIndex = getIndex;
- }
- LOG.semaphore = 0; /* Free semaphore */
- }
- }
- #endif /* GENERATE_GLUE */
- return (status);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * CopyLogEntry
- *
- * Copy the specified LogRecord entry. This returns a copy of the entry, return TRUE
- * if it was in range. This is only used by the DCMD to snapshot a LogRecord.
- */
- pascal OSErr
- CopyLogEntry(
- LogRecordPtr logRecordPtr, /* This log record */
- UInt32 getIndex, /* This entry index */
- LogEntryPtr thisLogEntry /* Store entry here */
- )
- {
- OSErr status;
- #if GENERATE_GLUE
- CopyLogEntryProcPtr upp;
-
- status = ResolveLogLibraryLinkage(
- "\p_rdCopyLogEntry",
- (UniversalProcPtr *) &upp
- );
- if (status == noErr)
- status = (*upp)(logRecordPtr, getIndex, thisLogEntry);
- #else
- status = readErr;
- if (logRecordPtr != NULL && getIndex < LOG.entryMaxIndex) {
- if (CompareAndSwap(0, 1, &LOG.semaphore) == FALSE) { /* Grab semaphore */
- IncrementAtomic((SInt32 *) &LOG.lostLockCounter); /* Oops, it's busy*/
- status = fBsyErr; /* Inform caller */
- }
- else { /* Nope, we got it */
- status = noErr; /* Inform caller */
- *thisLogEntry = LOG.entries[getIndex]; /* Store result */
- LOG.semaphore = 0; /* Free semaphore */
- }
- }
- #endif /* GENERATE_GLUE */
- return (status);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * LogLibraryUpTime
- *
- * Returns UpTime in nanoseconds. This can be called from 68000 code.
- */
- pascal void
- LogLibraryUpTime(
- Nanoseconds *resultPtr
- )
- {
- #if GENERATE_GLUE
- OSErr status;
- LogLibraryUpTimeProcPtr upp;
-
- status = ResolveLogLibraryLinkage(
- "\p_rdLogLibraryUpTime",
- (UniversalProcPtr *) &upp
- );
- if (status == noErr)
- (*upp)(resultPtr);
- else {
- resultPtr->hi = resultPtr->lo = 0;
- }
- #else
- volatile AbsoluteTime now; /* Prevent a compiler bug */
-
- now = UpTime();
- *resultPtr = AbsoluteToNanoseconds(now);
- #endif /* GENERATE_GLUE */
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * LogLibraryAbsoluteToNanoseconds
- *
- * AbsoluteToNanoseconds. This can be called from 68000 code.
- */
- pascal void
- LogLibraryAbsoluteToNanoseconds(
- const AbsoluteTime *sourcePtr,
- Nanoseconds *resultPtr
- )
- {
- #if GENERATE_GLUE
- OSErr status;
- LogLibraryAbsoluteToNanosecondsProcPtr upp;
-
- status = ResolveLogLibraryLinkage(
- "\p_rdLogLibraryAbsoluteToNanoseconds",
- (UniversalProcPtr *) &upp
- );
- if (status == noErr)
- (*upp)(sourcePtr, resultPtr);
- else {
- resultPtr->hi = resultPtr->lo = 0;
- }
- #else
- *resultPtr = AbsoluteToNanoseconds(*sourcePtr);
- #endif /* GENERATE_GLUE */
-
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * EnableLogRecord
- *
- * Enable/disable logging. Returns the old logging state.
- */
- pascal Boolean32
- EnableLogRecord(
- LogRecordPtr logRecordPtr, /* This log record */
- Boolean32 enableLogging
- )
- {
- Boolean32 result;
- #if GENERATE_GLUE
- EnableLogRecordProcPtr upp;
-
- if (ResolveLogLibraryLinkage(
- "\p_rdEnableLogRecord",
- (UniversalProcPtr *) &upp)
- != noErr)
- result = FALSE;
- else {
- result = (*upp)(logRecordPtr, enableLogging);
- }
- #else
- UInt32 oldFlag;
- UInt32 newFlag;
-
- if (logRecordPtr == NULL)
- oldFlag = 0;
- else {
- do {
- oldFlag = LOG.flags;
- if (enableLogging)
- newFlag = oldFlag | kLogDataEnabledMask;
- else {
- newFlag = oldFlag & ~kLogDataEnabledMask;
- }
- } while (CompareAndSwap(oldFlag, newFlag, &LOG.flags) == FALSE);
- }
- result = ((oldFlag & kLogDataEnabledMask) != 0);
- #endif /* GENERATE_GLUE */
- return (result);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * PreserveLogRecord
- *
- * Set the preserveFirst flag. Returns the old flag value.
- */
- pascal Boolean32
- PreserveLogRecord(
- LogRecordPtr logRecordPtr, /* This log record */
- Boolean32 preserveFirst
- )
- {
- Boolean32 result;
- #if GENERATE_GLUE
- PreserveLogRecordProcPtr upp;
-
- if (ResolveLogLibraryLinkage(
- "\p_rdPreserveLogRecord",
- (UniversalProcPtr *) &upp)
- != noErr)
- result = FALSE;
- else {
- result = (*upp)(logRecordPtr, preserveFirst);
- }
- #else
- UInt32 oldFlag;
- UInt32 newFlag;
-
- if (logRecordPtr == NULL)
- oldFlag = 0;
- else {
- do {
- oldFlag = LOG.flags;
- if (preserveFirst)
- newFlag = oldFlag | kLogDataPreserveFirstMask;
- else {
- newFlag = oldFlag & ~kLogDataPreserveFirstMask;
- }
- } while (CompareAndSwap(oldFlag, newFlag, &LOG.flags) == FALSE);
- }
- result = ((oldFlag & kLogDataPreserveFirstMask) != 0);
- #endif /* GENERATE_GLUE */
- return (result);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * GetLogSemaphoreLostCounter
- *
- * Because the log library uses a "lossy" algorithm to maintain exclusive access to
- * the critical section, there is a very slight possibility that two processes will
- * try to access the log record at the same time. In this case, ReadLogEntry will
- * stall (loop) and eventually succeed, while WriteLogEntry will lose the datum, and
- * increment the logLostCounter.
- */
- pascal UInt32
- GetLogSemaphoreLostCounter(
- LogRecordPtr logRecordPtr /* This log record */
- )
- {
- UInt32 result;
- #if GENERATE_GLUE
- GetLogSemaphoreLostCounterProcPtr upp;
-
- if (ResolveLogLibraryLinkage(
- "\p_rdGetLogSemaphoreLostCounter",
- (UniversalProcPtr *) &upp)
- != noErr)
- result = 0;
- else {
- result = (*upp)(logRecordPtr);
- }
- #else
- result = ((logRecordPtr == NULL) ? 0 : LOG.lostLockCounter);
- #endif /* GENERATE_GLUE */
- return (result);
- }
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * LogRecord utilities.
- *
- * These three functions are used to locate all registered log records. They may be
- * used for a display utility or MacsBug dcmd. Applications call them as follows:
- *
- * LogRecordIter cookie;
- *
- * if (LogRecordIterateCreate(&cookie) == noErr) {
- * while ((logRecordPtr = LogRecordIterate(&cookie)) != NULL) {
- * ... Process this LogRecord, the name may be extracted from the record ...
- * }
- * LogRecordIterateDispose(&cookie);
- * }
- */
- pascal OSErr
- LogRecordIterateCreate(
- LogRecordIterPtr cookie
- )
- {
- OSErr status;
- #if GENERATE_GLUE
- LogRecordIterateCreateProcPtr upp;
-
- status = ResolveLogLibraryLinkage(
- "\p_rdLogRecordIterateCreate",
- (UniversalProcPtr *) &upp
- );
- if (status == noErr) {
- status = (*upp)(cookie);
- if (status != noErr) {
- PutSigned(status);
- PutPascalString("\p: LogRecordIterateCreate failed");
- PutLine();
- }
- }
- #else
- if (FindOrCreateLogRegistryEntryID() == FALSE)
- status = paramErr; /* Need correct error */
- else {
- status = RegistryPropertyIterateCreate(
- &gLogEntryID,
- &cookie->propertyIterCookie
- );
- }
- #endif /* GENERATE_GLUE */
- return (status);
- }
-
- pascal void
- LogRecordIterateDispose(
- LogRecordIterPtr cookie
- )
- {
- #if GENERATE_GLUE
- LogRecordIterateDisposeProcPtr upp;
-
- if (ResolveLogLibraryLinkage(
- "\p_rdLogRecordIterateDispose",
- (UniversalProcPtr *) &upp) == noErr) {
- (*upp)(cookie);
- }
- #else
- RegistryPropertyIterateDispose(&cookie->propertyIterCookie);
- #endif /* GENERATE_GLUE */
- }
-
- pascal LogRecordPtr
- LogRecordIterate(
- LogRecordIterPtr cookie
- )
- {
- LogRecordPtr logRecordPtr;
- #if GENERATE_GLUE
- LogRecordIterateProcPtr upp;
-
- if (ResolveLogLibraryLinkage(
- "\p_rdLogRecordIterate",
- (UniversalProcPtr *) &upp)
- != noErr)
- logRecordPtr = NULL;
- else {
- logRecordPtr = (*upp)(cookie);
- }
- #else
- OSErr status;
- Boolean done;
- RegPropertyNameBuf property;
- RegPropertyValueSize actualSize;
-
- do {
- status = RegistryPropertyIterate(
- &cookie->propertyIterCookie,
- property,
- &done
- );
- } while (status == noErr
- && done == FALSE
- && CStrCmp(kReservedPropertyName, property) == 0);
- if (status != noErr || done)
- logRecordPtr = NULL;
- else {
- actualSize = sizeof logRecordPtr;
- status = RegistryPropertyGet(
- &gLogEntryID,
- property,
- &logRecordPtr,
- &actualSize
- );
- if (status != noErr || actualSize != sizeof logRecordPtr)
- logRecordPtr = NULL;
- }
- #endif /* GENERATE_GLUE */
- return (logRecordPtr);
- }
-
-
- #if GENERATE_GLUE
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * ResolveLogLibraryLinkage
- *
- * This function is called (only on 68000 compilations) to form the Mixed Mode
- * routine descriptor. Originally, it stored the pointer in a static location (owned
- * by the caller), but this failed when called from a dcmd.
- */
- static OSErr
- ResolveLogLibraryLinkage(
- ConstStr255Param symbolRDName,
- UniversalProcPtr *uppPtr /* Pointer to static upp */
- )
- {
- OSErr status;
- CFragConnectionID connID;
- Ptr mainAddr; /* Main address: unused */
- Str255 errorName; /* Fragment failure text */
- CFragSymbolClass symbolClass; /* Symbol class (unused) */
-
- status = GetSharedLibrary(
- kLogSharedLibraryName,
- kPowerPCCFragArch,
- kLoadCFrag,
- &connID,
- &mainAddr,
- errorName
- );
- #if TEST_DCMD
- if (status != noErr) {
- PutSigned(status);
- PutPascalString("\p: GetSharedLibrary failed");
- PutLine();
- PutPascalString("\pCan't resolve ");
- PutPascalString(errorName);
- PutLine();
- }
- #endif
- if (status == noErr) {
- /*
- * We have the library (but we've never seen this function),
- * locate its Routine Descriptor in the library
- */
- status = FindSymbol(
- connID,
- symbolRDName,
- (Ptr *) uppPtr,
- &symbolClass
- );
- #if TEST_DCMD
- if (status != noErr) {
- PutSigned(status);
- PutPascalString("\p: FindSymbol failed");
- PutLine();
- PutPascalString("\pCan't find symbol: ");
- PutPascalString(symbolRDName);
- PutLine();
- }
- #endif
- if (status == noErr && symbolClass != kDataCFragSymbol)
- status = paramErr; /* Bug: name isn't a function */
- }
- return (status);
- }
- #endif
-
- #if GENERATE_GLUE == 0
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * These are the only functions that know about the Name Registry -- well, except for
- * the iterators, of course.
- */
-
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * CreateLogRecord
- *
- * This function manipulates the System Name Registry to create or lookup the named
- * log record.
- */
-
- static LogRecordPtr
- CreateLogRecord(
- const LogRecordNamePtr logRecordNamePtr, /* Driver Log name */
- UInt32 nEntries /* Number of Log entries */
- )
- {
- OSErr status;
- LogRecordPtr logRecordPtr; /* This driver log */
- ByteCount logRecordSize;
-
- logRecordPtr = FindLogRecordPtr(logRecordNamePtr);
- if (logRecordPtr == NULL && gFoundLogEntryStatus == kLogEntryOK) {
- /*
- * The log record is not in the registry entry (possibly because we
- * just created it. Add this name as a new property.
- *
- * Hand-compute the LogEntryRecord size to make sure that compiler quirks
- * don't mess us up. We check that kSizeofLogEntry equals sizeof
- * (LogEntryRecord). The ANSI C Standard does not permit "sizeof" in a
- * #define statement, so this check must be made at runtime.
- *
- * Note: do not replace the hard-coded numbers by sizeof statements:
- * this strange sequence ensures that the library can be complied
- * by several compilers.
- */
- #define kSizeofLogRecordEntry \
- ( 8 /* sizeof eventTime */ \
- + 4 /* sizeof sequence */ \
- + 4 /* sizeof idCode */ \
- + 4 /* sizeof format */ \
- + (4 * kLogEntryDataSize) /* sizeof data[] */ \
- )
- if (sizeof (LogEntryRecord) == kSizeofLogRecordEntry /* Size ok? */
- && nEntries > 0) { /* Has entries? */
- /*
- * We must create a new log record storing a pointer to it as a
- * property in the Name Registry. The actual record has one extra
- * entry to prevent the "full vs. empty" bug.
- */
- logRecordSize = sizeof (LogRecord)
- + (nEntries * sizeof (LogEntryRecord));
- logRecordPtr = (LogRecordPtr)
- PoolAllocateResident(logRecordSize, TRUE);
- if (logRecordPtr != NULL) {
- status = RegistryPropertyCreate(
- &gLogEntryID,
- (RegPropertyNamePtr) logRecordNamePtr,
- &logRecordPtr,
- sizeof logRecordPtr
- );
- if (status != noErr) {
- (void) PoolDeallocate((LogicalAddress) logRecordPtr);
- logRecordPtr = NULL;
- }
- }
- }
- }
- exit: return (logRecordPtr);
- }
-
- /*
- * Find the log record, creating the log registry entry if necessary.
- */
- LogRecordPtr
- FindLogRecordPtr(
- const LogRecordNamePtr logRecordNamePtr /* Driver Log name */
- )
- {
- OSErr status;
- RegPropertyValueSize actualSize;
- LogRecordPtr logRecordPtr;
-
- logRecordPtr = NULL;
- if (logRecordNamePtr[0] != EOS /* real string? */
- && CStrCmp(kReservedPropertyName, logRecordNamePtr) != 0) {/* not "name"? */
- if (FindOrCreateLogRegistryEntryID()) {
- actualSize = sizeof logRecordPtr;
- status = RegistryPropertyGet(
- &gLogEntryID,
- (RegPropertyNamePtr) logRecordNamePtr,
- &logRecordPtr,
- &actualSize
- );
- if (status != noErr || actualSize != sizeof logRecordPtr)
- logRecordPtr = NULL;
- }
- }
- return (logRecordPtr);
- }
-
- Boolean
- FindOrCreateLogRegistryEntryID(void)
- {
- OSErr status;
-
- if (gFoundLogEntryStatus == kFirstCall) {
- status = RegistryCStrEntryLookup(
- NULL, kLogRegistryEntry, &gLogEntryID);
- if (status != noErr) {
- status = RegistryCStrEntryCreate(
- NULL, kLogRegistryEntry, &gLogEntryID);
- }
- gFoundLogEntryStatus = (status == noErr)
- ? kLogEntryOK : kLogEntryFailed;
- }
- return (gFoundLogEntryStatus == kLogEntryOK);
- }
-
- #endif /* Functions that are only available to the actual library */
-
-
-